import tkinter as tk
import constants as const
from eventcenter import eventcenter as event
from datacenter import datacenter as dc
from tools import tools

class LeftMenuGuide(tk.Frame):
    """左侧菜单导航类，用于显示和管理卡片层级
    
    该类继承自tk.Frame，负责显示特定层级的卡片列表，并处理卡片的选择、添加和删除操作。
    """
    
    def __init__(self, root, layerid=const.NONE_INT):
        """初始化左侧菜单导航
        
        Args:
            root: 父级窗口组件
            layerid: 层级ID，默认为NONE_INT(-1)
        """
        super().__init__(root)
        self.root = root

        self.layerid = layerid
        self.current_selected = const.UNSELECTED  # 当前选中的卡片索引
        self.buttons = []  # 卡片按钮列表

        self.init_event(self)

        # 创建容器 Frame
        self.create_widgets()

    def get_uids(self):
        """获取当前层级的卡片UID列表
        
        Returns:
            list: 当前层级的卡片UID列表，如果层级无效则返回空列表
        """
        if self.layerid < 0 or self.layerid >= len(dc.curmap.cuids):
            return []
        return dc.curmap.cuids[self.layerid]
        
    def init_event(self, *args):
        """初始化事件监听
        
        注册卡片选择、卡片值变更和卡片索引变更的事件处理函数
        
        Args:
            *args: 可变参数列表
        """
        event.add_event(const.event_select_card, self.event_select_card)
        event.add_event(const.event_card_value_changed, self.event_card_value_changed)
        
    def calculate_height(self):
        """计算组件的总高度
        
        Returns:
            int: 所有子组件的总高度
        """
        children = self.winfo_children()
        height = 0
        for child in children:
            height += child.winfo_reqheight()
        return height
        
    def select_card(self, card_id=const.UNSELECTED):
        """根据卡片ID选择卡片
        
        Args:
            card_id: 要选择的卡片ID，默认为UNSELECTED(-1)
        """
        uids = self.get_uids()
        if card_id in uids:
            index = uids.index(card_id)
        else:
            index = -1

        self.select_card_index(index)

    def select_card_index(self, index=const.UNSELECTED):
        """根据索引选择卡片
        
        Args:
            index: 要选择的卡片索引，默认为UNSELECTED(-1)
        """
        previous = self.current_selected
        if index is not None and previous >= 0 and previous < len(self.buttons):
            self.buttons[previous].config(bg=const.unselect_color)

        self.current_selected = index
        if previous == index:
            return

        if index is not None and index >= 0 and index < len(self.buttons):
            self.buttons[index].config(bg=const.select_color)

    def get_card_count(self):
        """获取卡片数量
        
        Returns:
            int: 卡片数量
        """
        return len(self.get_uids())

    def create_widgets(self):
        """创建界面组件
        
        创建按钮框架和控制按钮，并初始化层级显示
        """
        # 创建按钮容器框架
        self.buttons_frame = tk.Frame(self, width=50)  # 限制整体宽度
        self.buttons_frame.pack(side=tk.TOP, fill=tk.Y)
        self.buttons_frame.pack_propagate(False)  # 防止子组件撑大Frame

        # 创建控制按钮区域
        control_frame = tk.Frame(self.buttons_frame)
        control_frame.grid(column=0, row=0, sticky='w', padx=2)
        tk.Label(control_frame, text=f"Layer:{self.layerid}", width=6).pack(side=tk.LEFT, padx=2)
        tk.Button(control_frame, text="+", command=self.add_new_card, width=2).pack(side=tk.LEFT, padx=2)
        tk.Button(control_frame, text="-", command=self.delete_card, width=2).pack(side=tk.LEFT, padx=2)

        # 刷新层级显示
        self.refresh_layer()

    def set_cards(self, card_ids, index=const.NONE_INT, force_refresh=False):
        """设置卡片列表
        
        Args:
            card_ids: 卡片ID列表或单个卡片ID
            index: 要设置的索引位置，默认为NONE_INT(-1)表示设置整个列表
            force_refresh: 是否强制刷新界面，默认为False
        """
        if index != const.NONE_INT:
            dc.curmap.cuids[self.layerid][index] = card_ids
        else:
            dc.curmap.cuids[self.layerid] = card_ids

        if force_refresh:
            self.refresh_layer()

    def add_new_card(self):
        """添加新卡片
        
        在当前层级添加一张新卡片，并刷新界面
        
        Returns:
            None: 如果地图未加载，则返回None
        """
        if not dc.curmap.isLoad():
            return tools.show_tip_info("请先加载地图")

        # 获取新卡片的UID和索引
        uid = dc.get_uid()
        uids = dc.curmap.cuids[self.layerid]
        index = len(uids)
        
        # 设置新卡片的初始位置
        x = const.game_window_width + const.fix_distance
        dc.curmap.new_card(uid, self.layerid, index, x, const.fix_distance)

        # 刷新界面并触发事件
        self.refresh_layer()
        event.dispatch_event(const.event_on_new_card, uid, self.layerid, index)
    
    def delete_card(self):
        """删除卡片
        
        删除当前选中的卡片或最后一张卡片，并刷新界面
        
        Returns:
            None: 如果地图未加载，则返回None
        """
        if not dc.curmap.isLoad():
            return tools.show_tip_info("请先加载地图")

        cuids = dc.curmap.cuids
        if len(cuids) > 0:
            uids = cuids[self.layerid]
            # 如果有选中的卡片则删除选中的，否则删除最后一张
            index = self.current_selected if self.current_selected >= 0 else len(uids) - 1
            if index >= 0:
                uid = uids[index]
                dc.curmap.del_card(uid)
                self.current_selected = const.UNSELECTED
                # 刷新界面并触发事件
                self.refresh_layer()
                event.dispatch_event(const.event_on_del_card, uid)

    def on_card_click(self, et):
        """卡片点击事件处理函数
        
        处理卡片按钮的点击事件，切换卡片的选中状态并触发菜单点击事件
        
        Args:
            et: 点击事件对象
        """
        # 获取点击的按钮索引和对应的卡片UID
        index = self.buttons.index(et.widget)
        uid = self.get_uids()[index]
        
        # 如果点击已选中的卡片则取消选中，否则选中点击的卡片
        self.select_card_index(index if self.current_selected == index else const.UNSELECTED)

        # 触发菜单点击事件
        event.dispatch_event(const.event_guide_menu_cliciked, uid, self.layerid, index)

    def refresh_layer(self):
        """刷新层级显示
        
        根据当前层级的卡片列表刷新界面显示
        """
        count = 0
        uids = self.get_uids()
        
        # 遍历当前层级的所有卡片
        for i, card_id in enumerate(uids):
            count += 1
            button = self.buttons[i] if i < len(self.buttons) else None
            card_data = dc.get_card(card_id)
            
            if card_data: 
                # 如果按钮不存在则创建新按钮
                if not button:
                    button = tk.Button(self.buttons_frame)
                    button.config(text=f'{i}  [{card_data.card_str()}]')
                    button.bind("<Button-1>", self.on_card_click)
                    button.grid(column=0, row=i+1, sticky='nw')
                    self.buttons.append(button)
                # 如果按钮已存在则更新文本
                else:
                    button.config(text=f'{i}  [{card_data.card_str()}]')
                    # 如果按钮未显示则显示按钮
                    if not button.winfo_ismapped():
                        button.grid(column=0, row=i+1, sticky='nw')

        # 隐藏多余的按钮
        if count < len(self.buttons):
            for i in range(count, len(self.buttons)):
                self.buttons[i].grid_forget()

        # 触发菜单刷新事件
        event.dispatch_event(const.event_on_menu_refreh)

    def clear(self):
        """清除所有按钮显示
        
        隐藏所有卡片按钮
        """
        for button in self.buttons:
            button.grid_forget()

    def event_select_card(self, uid, selected):
        """卡片选择事件处理函数
        
        处理卡片选择事件，更新界面中卡片的选中状态
        
        Args:
            uid: 卡片UID
            selected: 是否选中
        """
        card_data = dc.get_card(uid)
        # 如果卡片属于当前层级，则更新选中状态
        if card_data and card_data.layerid == self.layerid:
            index = self.get_uids().index(uid)
            if index >= 0:
                self.select_card_index(index if selected else const.UNSELECTED)
        # 如果卡片不属于当前层级但被选中，则取消当前层级的选中状态
        else:
            if selected:
                self.select_card_index(const.UNSELECTED)

    def event_card_value_changed(self, uid, refreshall = False):
        if refreshall:
            self.refresh_layer()
        else:
            uids = self.get_uids()
            if uid in uids:
                index = uids.index(uid)
                # 添加索引范围检查，确保index在buttons列表范围内
                if index >= 0 and index < len(self.buttons):
                    self.buttons[index].config(text=f'{index}  [{dc.get_card(uid).card_str(True)}]')
        

    